001    /***********************************************************************************************
002     *              Tekijä:                 Jukka Salminen
003     *              Opiskelijanumero:       i79947
004     *              Email:                  jukka.salminen@uwasa.fi
005     *              Tekoaika:               23.9.2002
006     *              Kurssi/vuosi:           Ohjelmoinnin jatkokurssi/kevät 2002
007     *              Työn tunnus:            Harjoitustyö: Taulukkoeditori web-sivulle
008     ***********************************************************************************************
009     * JSTableModel-luokka
010     *====================
011     * JSTableModel-luokka toteuttaa JTableModel-rajapinnan ja suorittaa taulukon datan
012     * hakuun, muuttamiseen ja tallentamiseen tarvittavat toiminnot.
013     *
014     * Metodit
015     *--------
016     * initComponents       Muodostaa taulukon datavektorin
017     *
018     * addEmptyColumn       Lisää tyhjän sarakkeen taulukkoon
019     *
020     * addEmptyRow          Lisää tyhjän rivin taulukon loppuun
021     *
022     * createEmptyRow       Tuottaa sopivan mittaisen vektorin, jossa on
023     *                      sarakkeita vastaava määrä tyhjiä String-objekteja
024     *
025     * createEmptyColumn    Tuottaa uuden sarakeobjektin taulukkoon
026     *
027     * createNewHeader      Tuottaa uudelle sarakkeelle otsikon col1, col2 jne.
028     *
029     * getColumnIdentifiers Palauttaa taulukon sarakkeiden otsikot
030     *
031     * removeColumnAndData  Poistaa sarakkeen sekä taulukosta
032     *                      että taulukon datavektorista
033     *
034     * removeRow            Poistaa editoitavan rivin taulukosta
035     *
036     * insertRow            Lisää tyhjän rivin editoitavan rivin yläpuolelle
037     *
038     * save                 Tallentaa datan serverille HTTP POST:illa
039     *
040     * getTableData         Tuottaa DataHandler-objektin, joka lukee XML-parserin
041     *                      tuottamaa dataa. Palauttaa Datahandlerin tuottaman
042     *                      vektorin. Taulukon alkiot ovat datavektorissa.
043     *
044     * toXML                Tuottaa taulukon datavektorista XML-merkkijonon
045     *
046     * sortColumnIdentifiers  Korjaa sarakkeiden otsikot jo sarakkeita on lisätty
047     *                        tai niiden paikkoja vaihdettu
048     * Jäsenmuuttujat
049     *---------------
050     * m_sURL               Referenssi URL:ään, josta taulukkodata ladataan
051     *
052     * Paikalliset muuttujat
053     *----------------------
054     * Dokumentoitu metodien yhteydessä
055     */
056    
057    package tables;
058    import java.util.*;
059    import classes.*;
060    import javax.swing.table.*;
061    import jsxml.*;
062    import java.io.*;
063    import java.net.*;
064    
065    public class JSTableModel extends javax.swing.table.DefaultTableModel
066    {
067            String m_sURL;
068            public JSTableModel()
069            {
070                    initComponents();
071            }
072            
073            public JSTableModel(String sourceURL)
074            {
075                    initComponents(sourceURL);
076            }
077            
078            public void initComponents()
079            {
080                    // Testidataa Forten IDE:a varten
081                    setDataVector(new String [][]
082                    {
083                            {" ", " ", " ", " "},
084                            {" ", " ", " ", " "},
085                            {" ", " ", " ", " "},
086                            {" ", " ", " ", " "}
087                    },
088                    new String []
089                    {
090                            "Col1", "Col2", "Col3", "Col4"
091                    });
092            }
093            /***********************************************************************************************
094             * Metodi initComponents
095             * =====================
096             * Alustaa taulukon datavektorin
097             *
098             * Parametrit           sourceURL       URL, josta taulukon data haetaan
099             *
100             * Paikalliset muuttujat
101             *----------------------
102             * sDataVector          Vector, johon data kerätään
103             * maxCellsInRow        int, joka sisältää taulukon sarakkeiden lukumäärän
104             ***********************************************************************************************/
105            public void initComponents(String sourceURL)
106            {
107                    try
108                    {
109                            setURL(sourceURL);
110                            // sDataVectoriin haetaan taulukon data
111                            // Data on riveittäin, jokainen rivi on yksi vektorin sDataVector rivi
112                            Vector sDataVector = getTableData(sourceURL);
113                            // Rivit voivat olla erimittaisia ja on selvitettävä suurin rivinpituus
114                            // Selvitetään suurin sarakemäärä ja talletetaan maxCellsInRow:n arvoksi
115                            int maxCellsInRow=0;
116                            for (int i=0; i < sDataVector.size(); i++)
117                            {
118                                    if (((Vector)sDataVector.get(i)).size() > maxCellsInRow)
119                                    {
120                                            maxCellsInRow = ((Vector)sDataVector.get(i)).size();
121                                    }
122                            }
123                            // Luodaan sarakkeita varten vektori sColumnVector
124                            Vector sColumnVector = new Vector();
125                            for (int i=0; i < maxCellsInRow; i++)
126                            {
127                                    sColumnVector.add("Col"+(i+1));
128                                    //                      sColumnVector.add("Col2");
129                            }
130                            // Asetetaan JSTableModelin datavektori
131                            setDataVector(sDataVector, sColumnVector);
132                    }
133                    catch (NullPointerException exc)
134                    {
135                            initComponents();
136                            return;
137                    }
138            }
139            /***********************************************************************************************
140             * Metodi addEmptyColumn
141             * =====================
142             * Lisää tyhjän sarakkeen JSTable-taulukkoon ja tähän JSTableModeliin
143             *
144             * Parametrit           Ei ole
145             *
146             * Paikalliset muuttujat
147             *----------------------
148             * newHeader            String, jossa teksti "ColN", N = 1,2,3...
149             * newColumn            Vektori, jossa String-alkioita sopiva määrä
150             ***********************************************************************************************/
151            public void addEmptyColumn()
152            {
153                    String newHeader = createNewHeader();
154                    Vector newColumn = createEmptyColumn();
155                    addColumn(newHeader, newColumn);
156            }
157            /***********************************************************************************************
158             * Metodi addEmptyRow
159             * =====================
160             * Lisää tyhjän rivin JSTable-taulukkoon ja tähän JSTableModeliin
161             *
162             * Parametrit           Ei ole
163             *
164             * Paikalliset muuttujat
165             *----------------------
166             * newRow                       Vektori, jossa String-alkioita sopiva määrä
167             ***********************************************************************************************/
168            public void addEmptyRow()
169            {
170                    Vector newRow = createEmptyRow();
171                    addRow(newRow);
172            }
173            /***********************************************************************************************
174             * Metodi createEmptyRow
175             * =====================
176             * Luo ja palauttaa vektorin newRow, josta tulee uusi rivi tähän JSTableModeliin
177             *
178             * Parametrit           Ei ole
179             *
180             * Paikalliset muuttujat
181             *----------------------
182             * newRow                       Vektori, jossa String-alkioita sopiva määrä
183             ***********************************************************************************************/
184            private Vector createEmptyRow()
185            {
186                    Vector newRow = new Vector();
187                    for (int i=0; i < getColumnCount(); i++)
188                    {
189                            newRow.add(i, "");
190                    }
191                    return newRow;
192            }
193            /***********************************************************************************************
194             * Metodi createEmptyColumn
195             * =====================
196             * Luo ja palauttaa vektorin newColumn, josta tulee uusi sarake JSTableen
197             *
198             * Parametrit           Ei ole
199             *
200             * Paikalliset muuttujat
201             *----------------------
202             * newColumn            Vektori, jossa String-alkioita sopiva määrä
203             ***********************************************************************************************/
204            private Vector createEmptyColumn()
205            {
206                    Vector newColumn = new Vector();
207                    for (int i=0; i < getRowCount(); i++)
208                    {
209                            newColumn.add(i, "");
210                    }
211                    return newColumn;
212            }
213            /***********************************************************************************************
214             * Metodi createNewHeader
215             * =====================
216             * Luo ja palauttaa sarakeotsikon "ColN", jossa N on aina yhden suurempi kuin
217             * taulukon nykyinen sarakemäärä
218             *
219             * Parametrit           Ei ole
220             *
221             * Paikalliset muuttujat
222             *----------------------
223             * newHeader            String, joka sisältää uuden otsikon
224             ***********************************************************************************************/
225            private String createNewHeader()
226            {
227                    String newHeader = "Col"+(getColumnCount()+1);
228                    return newHeader;
229            }
230            /***********************************************************************************************
231             * Metodi getColumnIdentifirers
232             * ============================
233             * Palauttaa JSTableModelin sarakeotsikot vektorissa
234             ***********************************************************************************************/
235            public Vector getColumnIdentifiers()
236            {
237                    return columnIdentifiers;
238            }
239            /***********************************************************************************************
240             * Metodi removeColumnAndData
241             * ==========================
242             * Poistaa sarakkeen JSTable-taulukosta ja JSTableModelista. Täytyy poistaa sekä sarake
243             * JSTablen ColumnModelista että fyysinen data JSTableModelin datavektorista
244             *
245             * Parametrit           thisTable               JSTable-taulukko, joka käyttää tätä modelia
246             *
247             * Paikalliset muuttujat
248             *----------------------
249             * int colNumber                        Poistettavan sarakkeen indeksi = editoitavana oleva sarake
250             * TableColumn thisColumn       Poistettava sarakeobjekti thisSTable:ssa
251             * int columnModelIndex         TableModelissa olevan sarakkeen indeksi, joka vastaa sarakkeessa
252             *                                                      thisColumn olevan datan varastoinnista
253             * Vector thisData                      JSTableModelin datavektori
254             * Enumeration enum                     Apumuuttuja, joka sisältää TableColumnmodelin sarakkeet
255             *
256             ***********************************************************************************************/
257            public void removeColumnAndData(JSTable thisTable)
258            {
259                    int colNumber = thisTable.getEditingColumn();
260                    if (colNumber == -1)
261                    {
262                            return;
263                    }
264                    TableColumn thisColumn = thisTable.getColumnModel().getColumn(colNumber);
265                    int columnModelIndex = thisColumn.getModelIndex();
266                    Vector thisData = getDataVector();
267                    Vector columnIdentifiers = getColumnIdentifiers();
268                    
269                    // Remove the column from the table
270                    thisTable.removeColumn(thisColumn);
271                    
272                    // Tässä pitäisi tehdä kokonaan uudet otsikot
273                    columnIdentifiers.removeElementAt(columnModelIndex);
274                    // Remove the column data
275                    for (int r=0; r<thisData.size(); r++)
276                    {
277                            Vector row = (Vector)thisData.get(r);
278                            row.removeElementAt(columnModelIndex);
279                    }
280                    columnIdentifiers = getColumnIdentifiers();
281                    columnIdentifiers = sortColumnIdentifiers(columnIdentifiers);
282                    
283                    setDataVector(thisData, columnIdentifiers);
284                    // Correct the model indices in the TableColumn objects
285                    // by decrementing those indices that follow the deleted column
286                    Enumeration enum = thisTable.getColumnModel().getColumns();
287                    for (; enum.hasMoreElements(); )
288                    {
289                            thisColumn = (TableColumn)enum.nextElement();
290                            if (thisColumn.getModelIndex() >= columnModelIndex)
291                            {
292                                    thisColumn.setModelIndex(thisColumn.getModelIndex()-1);
293                            }
294                    }
295                    fireTableStructureChanged();
296            }
297            /***********************************************************************************************
298             * Metodi removeRow
299             * =================
300             * Poistaa rivin taulukosta ja taulukkomallista
301             *
302             * Parametrit           JSTable thisTable
303             *
304             * Paikalliset muuttujat
305             *----------------------
306             * int rowNumber                Poistettavan (editoitavan) rivin numero
307             ***********************************************************************************************/
308            public void removeRow(JSTable thisTable)
309            {
310                    int rowNumber = thisTable.getEditingRow();
311                    if (rowNumber == -1)
312                    {
313                            return;
314                    }
315                    // Remove the row from the table model
316                    getDataVector().remove(rowNumber);
317                    fireTableStructureChanged();
318            }
319            /***********************************************************************************************
320             * Metodi insertRow
321             * =================
322             * Lisää rivin taulukkoon editoitavan rivin yläpuolelle
323             *
324             * Parametrit           JSTable thisTable
325             *
326             * Paikalliset muuttujat
327             *----------------------
328             * int rowNumber                Editoitavan rivin numero
329             * Vector newRow                Lisättävä vektori
330             ***********************************************************************************************/
331            public void insertRow(JSTable thisTable)
332            {
333                    int rowNumber = thisTable.getEditingRow();
334                    if (rowNumber == -1)
335                    {
336                            return;
337                    }
338                    // Insert row above editing row
339                    Vector newRow = createEmptyRow();
340                    getDataVector().insertElementAt(newRow, rowNumber);
341                    fireTableStructureChanged();
342            }
343            /***********************************************************************************************
344             * Metodi save
345             * =================
346             * Tallettaa taulukon XML-muodossa serverille
347             * Samalla järjestetään taulukko uudelleen, jos sarakkeiden
348             * paikkoja on vaihdettu vetämällä
349             *
350             * Parametrit           JSTable thisTable
351             *
352             * Paikalliset muuttujat
353             *----------------------
354             * Vector vApu                  Apumuuttuja, jota käytetään taulukkoa järjestettessä
355             * Vector dataVector            Taulukkomallin datavektori
356             * Vector newdataVector         Taulukkomalliin sijoitettava uusi järjestetty datavektori
357             * Vector newRow                Uuteen datavektoriin sijoitettava rivivektori
358             * int iLines                   Datavektorin pituus, taulukon rivien lukumäärä
359             * Vector columnIdentifiers     Taulukon sarakeotsikot
360             * TableColumn thisColumn       Taulukon käsiteteltävänä oleva sarake
361             * Enumeration enum             Apumuuttuja, joka sisältää TableColumnModelin sarakkeet
362             * int i, r                     Laskurimuuttujia
363             ***********************************************************************************************/
364            public void save(JSTable thisTable)
365            {
366                    Vector vApu;
367                    Vector columnIdentifiers = sortColumnIdentifiers(getColumnIdentifiers());
368                    Vector dataVector = getDataVector();
369                    Vector newDataVector = new Vector(10,10);
370                    // Move the column data
371                    int iLines = dataVector.size();
372                    for (int r=0; r < iLines; r++)
373                    {
374                            // Jotta saataisiin kokonaan uusi datavektori täytyy luoda uusia rivejä newRow
375                            // Nämä rivit lisätään sitten uuteen datavektoriin newDataVector
376                            Vector newRow = new Vector(10,10);
377                            vApu = (Vector)dataVector.get(r);
378                            // Käydään järjestyksessä läpi kaikki taulukon sarakkeet
379                            // Etsitään datavektorista vastaava alkio ja lisätään se uuteen rivivektoriin
380                            Enumeration enum = thisTable.getColumnModel().getColumns();
381                            int i = 0;
382                            for (; enum.hasMoreElements(); )
383                            {
384                                    TableColumn thisColumn = (TableColumn)enum.nextElement();
385                                    int columnModelIndex = thisColumn.getModelIndex();
386                                    // vaihdetaan TableModelissa paikkaa
387                                    newRow.add(vApu.get(columnModelIndex).toString());
388                                    i++;
389                            }
390                            newDataVector.add(newRow);
391                    }
392                    // Asetetaan TableModeliin uusi datavektori ja päivitetään näkymää
393                    setDataVector(newDataVector, columnIdentifiers);
394                    fireTableStructureChanged();
395                    // Jos http-osoite, postataan XML serverille, muuten kirjoitetaan tiedostoon
396                    if (m_sURL.startsWith("http"))
397                    {
398                            post(toXML());
399                    }
400                    else
401                    {
402                            writeToFile(toXML());
403                    }
404            }
405            /***********************************************************************************************
406             * Metodi sortColumnIdentifiers
407             * =================
408             * Muodostaa uudet sarakeotsikot, jos sarakkeiden paikkoja on vaihdettu
409             * tai sarakkeita on poistettu
410             *
411             * Parametrit           Vector colIDs
412             *
413             * Paikalliset muuttujat
414             *----------------------
415             * Enumeration enum             Vektorin colIDs alkiot
416             * int i                        Laskurimuuttuja
417             * String thisHeader            Käsiteltävä sarakeotsikko
418             ***********************************************************************************************/
419            private Vector sortColumnIdentifiers(Vector colIDs)
420            {
421                    Enumeration enum = colIDs.elements();
422                    int i = 1;
423                    for (; enum.hasMoreElements(); )
424                    {
425                            String thisHeader = (String)enum.nextElement();
426                            thisHeader = "Col"+i;
427                            colIDs.setElementAt(thisHeader, i-1);
428                            i++;
429                    }
430                    return colIDs;
431            }
432            /***********************************************************************************************
433             * Metodi getTableData
434             * =================
435             * Hakee taulukkodatan URL-osoitteesta
436             *
437             * Parametrit           String sourceURL
438             *
439             * Paikalliset muuttujat
440             *----------------------
441             * DataHandler thisHandler     Palautettava DataHandler-objekti, joka kerää
442             *                             XML-parserin lukeman datan vektoriin
443             ***********************************************************************************************/
444            private Vector getTableData(String sourceURL)
445            {
446                    DataHandler thisHandler = new DataHandler(sourceURL);
447                    return thisHandler.get();
448            }
449            /***********************************************************************************************
450             * Metodi toXML
451             * =================
452             * Tekee datavektorista XML-stringin
453             *
454             * Parametrit           Ei ole
455             *
456             * Paikalliset muuttujat
457             *----------------------
458             * StringBuffer sb                      Tähän kerätään XML-merkkijono
459             * dataVector                           TableModelin datavektori
460             ***********************************************************************************************/
461            private String toXML()
462            {
463                    StringBuffer sb = new StringBuffer();
464                    Vector dataVector = getDataVector();
465                    if (dataVector.size() == 0)
466                    {
467                            return "";
468                    }
469                    // encoding voisi olla muukin kuin windows-1252
470                    // Pitäisi määritellä appletin parametreissa
471                    sb.append("<?xml version='1.0' encoding='windows-1252' ?>\n");
472                    sb.append("<table>\n");
473                    for (int r=0; r < dataVector.size(); r++)
474                    {
475                            sb.append("<tr>\n");
476                            Vector row = (Vector)dataVector.get(r);
477                            for (int i=0; i < row.size(); i++)
478                            {
479                                    sb.append("<td>"+row.get(i)+"</td>\n");
480                            }
481                            sb.append("</tr>\n");
482                    }
483                    sb.append("</table>");
484                    return sb.toString();
485            }
486            /***********************************************************************************************
487             * Metodi post
488             * =================
489             * HTTP-postaa XML-stringin serverille
490             *
491             * Parametrit           String XMLString
492             *
493             * Paikalliset muuttujat
494             *----------------------
495             * URL url                      URL johon postataan
496             * URLConnection con            Connection-objekti, saadaan url.openConnetion:illa
497             * String msg                   Post-muuttuja, joka luetaan serverillä. Sisältää XML-dataa
498             * OutputStream os              Outputstream, johon kirjoitetaan postattaessa
499             * OutputStreamWriter osw       OutputStreamWriter, joka huolehtii varsinaisesta kirjoittamisesta
500             * InputStream is               InputStream, jonka avulla luetaan serverin vastaus
501             * InputStreamReader isr        InputStreamReader, joka lukee serverin vastauksen
502             * BufferedReader bsr           Tämä on tätä JAVA-iota...
503             * String line                  Otetaan serveriltä tuleva data riveittäin tähän
504             ***********************************************************************************************/
505            private void post(String XMLString)
506            {
507                    try
508                    {
509                            // get the url as a string
510                            //                      String surl = "http://localhost/labonet/XMLtable.hb";
511                            //                      URL url = new URL(surl);
512                            URL url = new URL(m_sURL);
513                            URLConnection con = url.openConnection();
514                            //                      System.out.println("Received a : " + con.getClass().getName());
515                            con.setDoInput(true);
516                            con.setDoOutput(true);
517                            con.setUseCaches(false);
518                            
519                            String msg = "msg="+URLEncoder.encode(XMLString, "ISO-8859-1");
520                            con.setRequestProperty("CONTENT_LENGTH", "" + msg.length());
521                            OutputStream os = con.getOutputStream();
522                            OutputStreamWriter osw = new OutputStreamWriter(os);
523                            osw.write(msg);
524                            osw.flush();
525                            osw.close();
526                            
527                            InputStream is = con.getInputStream();
528                            // any response?
529                            InputStreamReader isr = new InputStreamReader(is);
530                            BufferedReader br = new BufferedReader(isr);
531                            String line;
532                            while (null != ((line = br.readLine())))
533                            {
534                                    //                              System.out.println("line: " + line);
535                            }
536                    }
537                    catch (Throwable t)
538                    {
539                            t.printStackTrace();
540                    }
541                    return;
542            }
543            /***********************************************************************************************
544             * Metodi setURL
545             * =================
546             * Asettaa jäsenmuuttujan m_sURL
547             *
548             * Parametrit           String SourceURL
549             ***********************************************************************************************/
550            public void setURL(String sourceURL)
551            {
552                    m_sURL = sourceURL;
553            }
554            /***********************************************************************************************
555             * Metodi writeToFile
556             * =================
557             * Testiohjelman käyttämä metodi, joka kirjoittaa levytiedostoon
558             *
559             * Parametrit          String XMLString
560             *
561             * Paikalliset muuttujat
562             *----------------------
563             * FileWriter thisFileWriter    Hoitaa kirjoittamisen
564             ***********************************************************************************************/
565            private void writeToFile(String XMLString)
566            {
567                    try
568                    {
569                            FileWriter thisFileWriter = new FileWriter(m_sURL);
570                            thisFileWriter.write(XMLString);
571                            thisFileWriter.close();
572                    }
573                    catch (Throwable t)
574                    {
575                            t.printStackTrace();
576                    }
577            }
578            // Overrided toString
579            public String toString()
580            {
581                    return toXML();
582            }
583    }